﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using PacketDotNet;
using System.Text.RegularExpressions;
using System.Threading;
using System.IO.Compression;
using System.IO;
/**
Nighthawk - ARP/ND spoofing, simple SSL stripping and password sniffing for Windows
 * Author: Wolfgang Christl

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/
namespace Nighthawk
{
    public class HttpResponseManagement
    {
        public static List<TcpPacket> ResponsePacketQueue = new List<TcpPacket>();
        private List<TcpPacket> ThreadResponsePacketQueue = new List<TcpPacket>();
        private Regex regexIsTextHTML = new Regex(@"DOCTYPE html", RegexOptions.Compiled | RegexOptions.Singleline);
        private Regex regexGZip = new Regex(@"Content-Encoding: gzip", RegexOptions.Compiled | RegexOptions.Singleline);
        private UTF8Encoding encoding = new UTF8Encoding();
        //uint nextSQN;
        //short sourceport;
        //string url;
        private List<byte> payloadHttp = new List<byte>();
        public byte[] payload;

        public HttpResponseManagement()
        {
        }

        #region HTTPCheckBack
        public void HttpCheckBack(uint nstartSQN, short nsourceport, string nurl)
        {
            //nextSQN = nstartSQN;
            //sourceport = nsourceport;
            //url = nurl;
        }

        public byte[] CheckBack(uint nextSQN, ushort destport, string url)
        {
            payloadHttp.Clear();

            #region HTTPCheckBack
            System.Diagnostics.Debug.WriteLine("");
            //System.Diagnostics.Debug.WriteLine("TCP Payload Length: " + packet.PayloadData.Length + " , Packet SQN number: " + packet.SequenceNumber);

            Thread.Sleep(150); //Wait so the Response packets can get into the ResponsePacketQueue
            
            #region copy requestpackets so we can process them
            lock (ResponsePacketQueue)
            {
                foreach (TcpPacket tcprespacket in ResponsePacketQueue)
                {
                    ThreadResponsePacketQueue.Add(tcprespacket);
                }

                ResponsePacketQueue.Clear();
            }
            System.Diagnostics.Debug.WriteLine("HttpResponseManagement: Seach for Responses for " + url);
            System.Diagnostics.Debug.WriteLine("HttpResponseManagement: Scanning " + ThreadResponsePacketQueue.Count + " packets for SQN: " + nextSQN + " DestPort: " + destport);
            #endregion

            #region Scan all Responsepackets for SQN
                foreach (TcpPacket ResPacket in ThreadResponsePacketQueue)
                {
                    System.Diagnostics.Debug.WriteLine("HRM: Packet: SQN: " + ResPacket.SequenceNumber + " Data:" + ResPacket.PayloadData.Length + " DestPort:" + ResPacket.DestinationPort);
                    //Find the start(s) of TCP Stream(s) (one TCP-Stream per port and IP at a time)
                    if (ResPacket.DestinationPort != destport || nextSQN != ResPacket.SequenceNumber || !ResPacket.ValidChecksum || ResPacket.PayloadData == null) continue;
                    System.Diagnostics.Debug.WriteLine("Test 1 -> OK");
                    if (ResPacket.Fin)
                    {
                        System.Diagnostics.Debug.WriteLine("All Packets here -> Decompress now if nescessary");
                        payload = payloadHttp.ToArray();

                        //Check Gzip
                        if (SimpleRegex.GetMatches(regexGZip, encoding.GetString(payload)).Count > 0)
                        {
                            System.Diagnostics.Debug.Write(" -> Gzip encoded -> Decompressing");
                            //Decompress Gzip
                            payload = Decompress(payload);
                            System.Diagnostics.Debug.Write(" -> Decompressed");
                        }
                        System.Diagnostics.Debug.WriteLine(payload);

                        //Check if it is Part of a html Website
                        //if (SimpleRegex.GetMatches(regexIsTextHTML, encoding.GetString(payload)).Count > 0)
                        //{
                        //    System.Diagnostics.Debug.WriteLine("HTTPCheckBack: Response is valid");
                        //}
                        //else
                        //{
                        //    System.Diagnostics.Debug.WriteLine("HTTPCheckBack: Response is not valid");
                        //}
                        break;
                    }
                    if (ResPacket.PayloadData.Length == 0) continue;

                    System.Diagnostics.Debug.WriteLine("HTTPCheckBack: Responses to SQN " + nextSQN + " found!");
                    payloadHttp.AddRange(ResPacket.PayloadData);
                    //Neue SQN jetzt setzen ?!
                }
            #endregion
            #endregion

            return payload;
        }
        #endregion

        public byte[] Decompress(byte[] gzip)
        {
            // Create a GZIP stream with decompression mode.
            // ... Then create a buffer and write into while reading from the GZIP stream.
            using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress))
            {
                const int size = 4096;
                byte[] buffer = new byte[size];
                using (MemoryStream memory = new MemoryStream())
                {
                    int count = 0;
                    do
                    {
                        count = stream.Read(buffer, 0, size);
                        if (count > 0)
                        {
                            memory.Write(buffer, 0, count);
                        }
                    }
                    while (count > 0);
                    return memory.ToArray();
                }
            }
        }
    }
}
